"""
20234-11-28 F 从飞书拉取任务群里的消息

"""

import json
import time
import datetime
from loguru import logger
import re
from dateutil import parser
import argparse
# import StyleFrame

import sys
import os
import requests

import pandas as pd

import lark_oapi as lark
from lark_oapi.api.im.v1 import *
from top.wardyan.core.wdb.core.DBPool import POOL
from config.Config import *

from lark_oapi.api.contact.v3 import *




SQL_FINDUSER = "exec yp_feishu_finduser @pMan='%s'"
SQL_SAVEUSER = "exec yp_feishu_saveuser @pMan='%s',@pName='%s'"
SQL_CLEANDATEMAN = "exec yp_feishu_cleandateman @pDate='%s', @pMan='%s'"
SQL_CLEANDATE = "exec yp_feishu_cleardate @pDate='%s'"
SQL_TASK = "exec yp_feishu_task @pDate='%s', @pMan='%s', @pName='%s',@pIsOK=%d,@pCust='%s',@pTaskID=%d,@pHour=%s,@pUpdateTime='%s',@pCode='%s'"
SQL_GETPREMSGTIME = "exec yp_feishu_getpremsgtime"
SQL_GETISCHANGE = "exec yp_feishu_getischange @pDate='%s', @pMan='%s', @pLastUpdate='%s' "

APPID = getconfig_str("feishu", "app_id")
APPSECRET = getconfig_str("feishu", "app_secret")
CONTAINERID = getconfig_str("feishu", "container_id")
TOKEN_URL = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
def token_request():
    token_json = {
        "app_id": APPID,
        "app_secret": APPSECRET
    }
    token_res = requests.post(TOKEN_URL, json=token_json)
    token_json = token_res.json()
 
    if token_res.status_code == 200 and token_json.get("code") == 0:
        return token_json.get('tenant_access_token')
    else:
        return None
def qrymanfromfeishu(uid : str):
    # 创建client
    # 使用 user_access_token 需开启 token 配置, 并在 request_option 中配置 token
    client = lark.Client.builder() \
        .enable_set_token(True) \
        .log_level(lark.LogLevel.DEBUG) \
        .build()

    # 构造请求对象
    request: GetUserRequest = GetUserRequest.builder() \
        .user_id(uid) \
        .build()

    # 发起请求
    token = token_request()
    option = lark.RequestOption.builder().tenant_access_token(token).build()
    response: GetUserResponse = client.contact.v3.user.get(request, option)

    # 处理失败返回
    if not response.success():
        lark.logger.error(
            f"client.contact.v3.user.get failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
        return

    # 处理业务结果
    data = response.data
    #lark.logger.info(lark.JSON.marshal(response.data, indent=4))
    # for data in datas.items :
    #     print(data)
    rs = uid
    try :
        rs = data.user.name
    except Exception as e :
        rs = uid
    return rs


    
def finduser(user) :
    """
    根据飞书ID找姓名
    """
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    cursor.execute(SQL_FINDUSER % user)
    data = cursor.fetchone()
    rs = None
    if data is not None :
        rs = data["xName"]

    if rs is None or rs == "":
        ## 先找一下这个人
        rs = qrymanfromfeishu(user)
        if rs is None or rs == "":
            rs = user
        cursor.execute(SQL_SAVEUSER % (user, rs))
        db.commit()
        rs = finduser(user)
    cursor.close()
    db.close()
    return rs
    

# def saveuser(code, name): 
#     """把用户名保存"""
#     db = POOL.connection()
#     cursor = db.cursor(as_dict=True)
#     cursor.execute(SQL_SAVEUSER % (code, name))
#     db.commit()
#     cursor.close()
#     db.close()




def cleardateman(date, man) :
    """
    清理某人某天指定的记录
    """
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    cursor.execute(SQL_CLEANDATEMAN % (date, man))
    db.commit()
    cursor.close()
    db.close()

def cleardateman(date) :
    """
    清理某人某天指定的记录
    """
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    cursor.execute(SQL_CLEANDATE % (date))
    db.commit()
    cursor.close()
    db.close()


def savetask(date, man, name, isok, cust, taskid, hour, updatetime, code) :
    """保存任务"""
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    print("savetask", date, man, name, isok, cust, taskid, hour, updatetime, code)
    cursor.execute(SQL_TASK % (date, man, name, isok, cust, taskid, hour, updatetime, code))
    db.commit()
    cursor.close()
    db.close()


def get_pre_msg_time() :
    """
    获取所下载的上一次消息的时间
    """
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    cursor.execute(SQL_GETPREMSGTIME)
    data = cursor.fetchone()
    rs = None
    if data is not None :
        rs = data["rResult"]
    cursor.close()
    db.close()
    return rs
    

def getischange(date : str, man : str, lastupdate : str)  -> bool:
    """
    获取所下载的上一次消息的时间
    """
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    cursor.execute(SQL_GETISCHANGE % (date, man, lastupdate))
    data = cursor.fetchone()
    rs : bool = True
    if data is not None :
        rs = bool(data["rResult"])
    cursor.close()
    db.close()
    return rs
    


FEISHUCLIENT = lark.Client.builder() \
    .app_id(APPID) \
    .app_secret(APPSECRET) \
    .log_level(lark.LogLevel.INFO) \
    .build()

def list(begintime : datetime.datetime) -> list:
    """
    列出群历史消息
    """
    # format = "%Y-%m-%d %H:%M:%S"
    # if len(begintime) <= 10 :
    #     format = "%Y-%m-%d 00:00:00"
    # elif len(begintime) <= 15 :
    #     format = "%Y-%m-%d  %H:%M:00"
    # t = time.strptime(begintime, format)
    # 构造请求对象
    # t = int(begintime)
    ## begintime
    ## 丢弃毫秒.
    t = int(datetime.datetime.timestamp(begintime))
    print("list timestamp:", t, begintime.strftime("%Y-%m-%d %H:%M:%S.%f"))
    
    ## 飞书接口时间戳是秒级, 是含这一秒. 这里接受进来的秒是上一次到哪一秒, 所以这一次加1秒
    request: ListMessageRequest = ListMessageRequest.builder() \
        .container_id_type("chat") \
        .container_id(CONTAINERID) \
        .start_time(t + 1) \
        .sort_type("ByCreateTimeAsc") \
        .page_size(50) \
        .build()

    # 发起请求
    response: ListMessageResponse = FEISHUCLIENT.im.v1.message.list(request)

    ## FEISHUCLIENT.auth.v3.tenant_access_token()

    # 处理失败返回
    if not response.success():
        lark.logger.error(
            f"client.im.v1.message.list failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
        return

    # 处理业务结果
    vs = response.data
    ks = lark.JSON.marshal(response.data, indent=4)
    ## vs.items.
    ## lark.logger.info(lark.JSON.marshal(response.data, indent=4))
    rs = []
    for item in vs.items :
        text = item.body.content
        sender = item.sender.id
        updatetime = item.update_time
        msgid = item.message_id
        ## print(item.body.content, item)
        # print(text,sender,updatetime,msgid)
        dict = {
            "text" : text,
            "sender" : sender,
            "updatetime" : updatetime,
            "msgid" : msgid
        }
        rs.append(dict)
    return rs


def spy(begindate : str) :
    page = 1
    format = "%Y-%m-%d %H:%M:%S"
    if len(begindate) <= 10 :
        format = "%Y-%m-%d 00:00:00"
    elif len(begindate) <= 15 :
        format = "%Y-%m-%d  %H:%M:00"
    ## t = time.strptime(begindate, format)
    if len(begindate) == 10 :
        begindate = begindate + " 00:00:00"
    t = datetime.datetime.strptime(begindate, format)

    ## 连续取得同一条消息就说明没有更多的消息了?
    while True :
        ## begintime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t))
        begintime : datetime.datetime = t
        print("list:", begintime.strftime("%Y-%m-%d %H:%M:%S.%f"))
        ls = list(begintime)
        print("page:", page, "size:", len(ls))
        if ls is None or len(ls) < 1 :
            print("done")
            break
        for item in ls :
            text = item["text"]
            sender = item["sender"]
            # updatetime
            updatetime = int(item["updatetime"])/1000
            msgid = item["msgid"]

            ## 拆分text内容
            ## print(text)
            ut = datetime.datetime.fromtimestamp(updatetime)
            parse(text, sender, ut, msgid)
            ## 找出最大的时间
            ## ut = time.strptime(updatetime, "%Y-%m-%d %H:%M:%S")
            ## print(updatetime)
            ## ut = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(updatetime))
            ## ut = time.localtime(updatetime)
            # print("t, ut:", int(time.mktime(t)), int(time.mktime(ut)))
            
            ## print("t, ut", t.strftime("%Y-%m-%d %H:%M:%S.%f"), ut.strftime("%Y-%m-%d %H:%M:%S.%f"))
            if ut > t :
                t = ut
        page+=1
        time.sleep(10)

        ## TODO 调试, 只取第1页回来
        

def normalize_date(date_str):
    try:
        # 尝试解析日期字符串
        parsed_date = parser.parse(date_str, fuzzy=True)
        # 格式化为 yyyy-MM-dd HH:mm:ss 格式
        normalized_date = parsed_date.strftime('%Y-%m-%d %H:%M:%S')
        return normalized_date
    except ValueError as e:
        # 如果解析失败，记录错误并返回原始字符串或自定义错误信息
        logger.warning(f"无法解析日期: {date_str}, 错误: {e}")
        return None
def parse(jsonstr : str, sender : str, updatetime : datetime.datetime, msgid : str) -> dict:
    ## ls : list = str.splitlines(text)
    ## print(ls)
    
    
    ## 解决<p></p>格式
    if "<p>" in jsonstr :
        ## print("before", jsonstr)
        # jsonstr = jsonstr.replace("<p>", "")
        # jsonstr = jsonstr.replace("</p>", "\n")
        jsonstr = re.sub(r'<p>', '', jsonstr)
        jsonstr = re.sub(r'<\/p>', '\n', jsonstr)
        ## print("after", jsonstr)
    
    try :
        js = json.loads(jsonstr)
        text = ""
        if "text" in js :
            ## 没有标记符号的
            text = js["text"]
            text = text.replace("\\n", "\n")
            lines = str.splitlines(text)
            print("lines:", lines)

            ## 第一行是日期, 格式可能很乱: 2024-09-6 2024-11-06 2024-9-6 2024年9月6日  2024年09月06日 2024年09月6日
            date  = normalize_date(lines[0])
            
            ## 根据用户UID取得用户名称
            user = finduser(sender)
            # .strftime("%Y-%m-%d %H:%M:%S.%f")
            tt = updatetime.strftime("%Y-%m-%d %H:%M:%S.%fff")[:-5]
            ischange : bool = getischange(date, user, tt)
            ## 判断是否有修改
            print(date, user, tt, "ischange:", ischange)
            if ischange :

                ## 第二行以后是任务内容
                for line in lines[1:] :
                    ## print(line)
                    ## 每行任务内容格式: 要求必须是: 兴雪莱 - 【ID1025007】任务名称 0.5h 未完成
                    ## 如果行以序号开始, 就去掉序号. 序号格式可能是1.这种
                    ## 其中最前面的客户名称可以没有, 最后面的未完成可以没有
                    line = re.sub(r'^\d+\.\s*', '', line)
                    isfinished : bool = True
                    if " 未完成" in line :
                        isfinished = False
                    line = re.sub(r'\s*未完成$', '', line)
                    line = line.rstrip()
                    id_match = re.search(r'【ID(\d+)】', line)
                    taskid = 0
                    if id_match:
                        taskid = int(id_match.group(1))
                    
                    # 查找小时数模式 0.5h
                    hour = 0.0
                    hour_match = re.search(r'(\d+(\.\d+)?)[hH]', line)
                    if hour_match:
                        hour = float(hour_match.group(1))
                    else:
                        hour = 0.0
                    print(date, line, taskid, hour, sender, user)
                    savetask(date, user, line, isfinished, "", taskid, hour, tt, msgid)
                    
            
        ## else ## 不支持这种格式,要求不能使用这种格式
        else :
            logger.warning("不支持这种格式:{}", jsonstr)
        ## print(text)
    except BaseException as e :
        logger.warning("解析错误:{}", e)

HELP = """

2024-12-03 F 从飞书任务群拉取任务记录.
配置文件放在: c:\\users\\xxx\\config.ini
配置文件示范:
## 2024-02-04 harrydeep@wardyan.top
## 开发环境配置
[db]
# 数据库类型: pymssql pymysql
type=pymssql
host=192.168.0.248
port=1433
user=feng
password=0400923
database=ERPDB4
exts=ERPDB
# 其他配置
[ERPDB]
host=
port=
user=
password=
database=
[feishu]
# 飞书应用配置
app_id=cli_a7cd887e25f8101c
app_secret=v3dc0kuc8HONEJ7fAB1gBeLOuXWyiNeJ
container_id=oc_660da37aaa220b88fdca87ea37a020bb


调用示范:
feishu 参数

参数说明: 
h : 显示本页说明
f : 强制重新读取. 需要用-t指定从什么时间开始.会先重置再读取
t : 从什么时间开始读取, 格式: 2024-11-01
d : 从飞书下载内容. 不指定-d的话就不下载
x : 指定生成一个excel统计
b : 使用-i时,用来指定开始日期
e : 使用-ii时,用来指定结束日期
"""

def toexcel(man : str, datekind : int, begin : str, end : str) :
    db = POOL.connection()
    cursor = db.cursor(as_dict=True)
    if man is None :
        man = ""
    if datekind is None :
        datekind = 0
    cursor.execute("exec yp_feishu_statistics @pMan='%s', @pDateKind=%d, @pBDate='%s', @pEDate='%s'" % (man, datekind, begin, end))
    data = cursor.fetchall()
    cursor.close()
    db.close()

    # 将数据转换为 DataFrame
    df = pd.DataFrame(data)

    # 定义 Excel 文件名
    excel_filename = f"{begin}_{end}_{man}_飞书.xlsx"

    # 将 DataFrame 写入 Excel 文件
    df.to_excel(excel_filename, index=False, engine='openpyxl')

    # excel_writer = StyleFrame.ExcelWriter('example.xlsx')
    # sf = StyleFrame(df)
    # sf.to_excel(
    #     excel_writer=excel_writer,
    #     best_fit=columns,
    #     columns_and_rows_to_freeze='B2',
    #     row_to_add_filters=0,
    # )
    # excel_writer.save()

    print(f"数据已成功写入 {excel_filename}")

def main():
    parser = argparse.ArgumentParser(description="从飞书任务群拉取任务记录", add_help=False)
    parser.add_argument('-t', '--time', type=str, help='从什么时间开始读取, 格式: 2024-11-01')
    parser.add_argument('-f', '--force', action='store_true', help='强制重新读取. 需要用-t指定从什么时间开始.会先重置再读取')
    parser.add_argument('-d', '--download', action='store_true', help='从飞书下载内容. 不指定-d的话就不下载')
    parser.add_argument('-h', '--help', type=str, help='帮助')
    parser.add_argument('-x', '--excel', action='store_true', help='指定生成一个excel统计')
    parser.add_argument('-b', '--begin', type=str, help='使用-i时,用来指定开始日期')
    parser.add_argument('-e', '--end', type=str, help='使用-i时,用来指定结束日期')
    parser.add_argument('-k', '--datekind', type=str, help='日期类型')
    parser.add_argument('-n', '--name', type=str, help='姓名')
    args = parser.parse_args()

    if args.help :
        print(HELP)
        return
    if args.download :
        if args.force:
            if args.time:
                pretime = args.time
                print(f"强制重新读取，从时间: {pretime} 开始")
                # 在这里添加重置逻辑
                cleardateman(pretime)
                spy(pretime)
            else:
                print("使用 -f 参数时，必须指定 -t 参数")
        else:
            pretime = get_pre_msg_time()
            spy(pretime)

    if args.excel :
        ## TODO 2024-12-03 先写个存储工程查询数据 再交给这里生成到EXCEL
        begin = args.begin
        end = args.end
        datekind = args.datekind
        name = args.name
        toexcel(name, datekind, begin, end)
        ## print(begin, end)

if __name__ == "__main__" :
    main()
    ## print(token_request())
    # print(qrymanfromfeishu("ou_646ca7deaf9c830cc51e7191401ff305"))
